#ifndef __LIGHT_ITEM_H__
#define __LIGHT_ITEM_H__

#include <cstdint>
#include <string>
#include <functional>
#include <initializer_list>
#include <vector>

/// @brief 单个灯的控制项，用于控制单个灯的亮度、颜色等
class LightItem
{
public:
    typedef uint8_t brightness_t;                          // 亮度类型
    typedef uint32_t delayms_t;                            // 延时类型
    typedef std::pair<brightness_t, delayms_t> flot_cmd_t; // 控制命令类型

    LightItem() = delete;
    virtual ~LightItem() = default;

    LightItem(std::function<void(void)> turn_on, std::function<void(void)> turn_off)
        : turn_on(turn_on), turn_off(turn_off)
    {
    }

    std::function<void(void)> turn_on;  // 打开函数
    std::function<void(void)> turn_off; // 关闭函数

    /// @brief 设置亮度
    /// @param brightness 亮度
    /// @note 亮度范围为0-100
    void set_brightness(brightness_t brightness)
    {
        __brightness = brightness; // 设置亮度
        if (__brightness == 0)
        {
            turn_off(); // 关闭灯
            return;
        }

        __brightness = std::min(__brightness, (brightness_t)100); // 限制亮度范围

        // 计算触发计数
        float ration = 100.0f / __brightness;
        __trun_on_count = __ctl_period * ration;           // 计算打开计数
        __trun_off_count = __ctl_period - __trun_on_count; // 计算关闭计数
    }

    /// @brief 执行控制命令
    /// @param delay_ms 延时时间
    /// @note 延时时间单位为毫秒
    void delayms(delayms_t delay_ms)
    {
        // TODO:延时delay_ms毫秒
    }

    /// @brief 执行控制命令
    /// @note 用于描述运行方式
    bool execute()
    {
        if (!__is_running)
        {
            return false; // 未执行控制命令
        }
        // 执行灯的控制
        __is_running = true;
        while (__is_running)
        {
            for (auto &cmd : __commands)
            {
                cmd();
            }
        }
        return true; // 执行成功
    }

    /// @brief 停止控制命令的执行
    /// @note 用于描述停止方式
    bool cancel()
    {
        if (!__is_running)
        {
            return false; // 未执行控制命令
        }
        __is_running = false;
        return true; // 停止成功
    }

    /// @brief 执行顺序控制命令，按照执行执行一次
    /// @param commands 控制命令{{亮度,延时时间},{亮度,延时时间},...}
    /// @return 是否执行成功
    /// @note 亮度范围为0-255，延时时间单位为毫秒
    /// @note 高度为0时表示关闭灯
    LightItem &flow(std::initializer_list<flot_cmd_t> commands)
    {
        __commands.push_back([commands, this]()
                             {
            for (auto &cmd : commands)
            {
                set_brightness(cmd.first);
                delayms(cmd.second);
            } });
        return *this;
    }

    /// @brief 执行循环控制命令
    /// @param loop_count 循环次数（0表示无限次循环）
    /// @param commands 控制命令{{亮度,延时时间},{亮度,延时时间},...}
    /// @return 是否执行成功
    /// @note 亮度范围为0-255，延时时间单位为毫秒
    LightItem &loop(uint32_t loop_count, std::initializer_list<flot_cmd_t> commands)
    {
        if (loop_count == 0)
        {
            // 无限循环
            __commands.push_back([commands, this]()
                                 {
                while (__is_running)
                {
                    flow(commands);
                } });
            return *this;
        }
        __commands.push_back([loop_count, commands, this]()
                             {
            for (uint32_t i = 0; i < loop_count || loop_count == 0; ++i)
            {
                flow(commands);
            } });
        return *this;
    }

    /// @brief 执行控制命令
    /// @return 自身引用
    LightItem &clear_cmds()
    {
        __commands.clear();
        return *this;
    }

    /// @brief 设置调光分辨率
    /// @param resolution 分辨率，其值越大，调光越精细，单位为pulse
    /// @note 用于描述灯的调光分辨率，表示resolution个脉冲为一个亮度调节周期
    /// @note 分辨率越高，灯的亮度越精细
    void set_resolution(uint32_t resolution)
    {
        __ctl_period = resolution;
    }

    /// @brief 显示亮度控制
    /// @param pulse 脉冲计数
    /// @note 用于调试灯的亮度，每当接收到脉冲时，计数就需要增加
    void update_pulse(const uint32_t &pulse)
    {
        if (__brightness == 0)
        {
            return; // 亮度为0，不点亮灯
        }
        uint32_t period_pulse = pulse % __ctl_period;
        bool should_be_on = period_pulse < __trun_on_count;

        if (should_be_on != __last_state) // 只在状态需要改变时才调用函数
        {
            if (should_be_on)
            {
                turn_on();
            }
            else
            {
                turn_off();
            }
            __last_state = should_be_on;
        }
    }

private:
    bool __is_running;    // 是否正在执行控制命令
    uint8_t __brightness; // 当前亮度，范围0-100

    std::vector<std::function<void(void)>> __commands; // 控制命令

    uint32_t __ctl_period{100}; // 控制周期，单位pulse

    uint32_t __trun_on_count{50};  // 打开计数次数
    uint32_t __trun_off_count{50}; // 关闭计数次数
    bool __last_state{false};      // 记录上一次的状态
};

#endif // __LIGHT_ITEM_H__